import Cesium, { Cartesian3, PolylineCollection } from '../Ces/Cesium';
import Config from '../Core/Config';
import WeatherVolumeWallAxisGeometry from './WeatherVolumeWallAxisGeometry';

/**
 * @private
 */
interface WallOptions {
    [key: string]: any;
}

class WeatherVolumeLibrary {
    /**
     * Creates a wall outline using a polyline collection
     * @param wallPositions Array of wall positions
     * @param floors Array of floor values
     * @param options Options for the polyline
     * @returns PolylineCollection containing the wall outlines
     */
    static createWallOutline(wallPositions: number[], floors: number[], options: WallOptions): PolylineCollection {
        const polylineCollection = new Cesium.PolylineCollection();
        const floorPositions = WeatherVolumeWallAxisGeometry.computePositions(
            Cesium.Ellipsoid.WGS84,
            wallPositions,
            floors,
            Cesium.Math.RADIANS_PER_DEGREE * Config.granularityFactor,
        );
        const st: Cartesian3[] = [];
        const ed: Cartesian3[] = [];

        const floorNum = floorPositions.floorPositions.length;
        const length = floorPositions.floorPositions[0].length / 3;

        for (let f = 0; f < floorNum; f++) {
            const fositions = floorPositions.floorPositions[f];
            const linepos: Cartesian3[] = [];

            for (let i = 0; i < length; ++i) {
                const position = Cesium.Cartesian3.fromArray(
                    fositions,
                    i * 3,
                    new Cesium.Cartesian3(),
                );

                linepos.push(position);
                if (i === 0) {
                    st.push(position);
                } else if (i === length - 1) {
                    ed.push(position);
                }
            }
            polylineCollection.add({
                positions: linepos,
                ...options,
            });
        }
        polylineCollection.add({
            positions: st,
            ...options,
        });
        polylineCollection.add({
            positions: ed,
            ...options,
        });

        return polylineCollection;
    }

    /**
     * Computes wall positions between two points
     * @param p1 First point
     * @param p2 Second point
     * @param granularityFactor Factor for granularity calculation
     * @returns Array of Cartesian3 positions
     */
    static computeWallPosition(p1: Cartesian3, p2: Cartesian3, granularityFactor: number): Cartesian3[] {
        const dx = (p1.x > p2.x) ? p1.x - p2.x : p2.x - p1.x;
        const dy = (p1.y > p2.y) ? p1.y - p2.y : p2.y - p1.y;
        const granularity = Cesium.Math.RADIANS_PER_DEGREE * granularityFactor;
        const width = Math.ceil(dx / granularity) + 1;
        const height = Math.ceil(dy / granularity) + 1;

        const stamp = width > height ? width : height;
        const granularityX = (p2.x - p1.x) / (stamp - 1);
        const granularityY = (p2.y - p1.y) / (stamp - 1);
        const granYCos = granularityY;
        const granXCos = granularityX;

        const size = stamp * 2;
        const pos = new Float64Array(size);

        for (let i = 0; i < size; i += 2) {
            pos[i] = p1.x + (i / 2) * granXCos;
            pos[i + 1] = p1.y + (i / 2) * granYCos;
        }

        return Cesium.Cartesian3.fromRadiansArray(pos);
    }
}

export default WeatherVolumeLibrary;
